// 扩展
#include "../logs/logslearn.h"

/*扩展一个以时间作为日志文件滚动切换类型的日志落地模块
   1.以时间进行文件滚动，实际上是以时间段进行滚动
       实现思想：以当前系统时间，取模获得时间段大小，可以得到当前时间段是第几个时间段
           time(nullptr)%gap;
           每次以当前系统时间取模，判断与当前文件的时间段是否一致，不一致代表不是同一个时间段
   */
// 使用枚举来确定时间段的大小
enum class TimeGap
{
    GAP_SECOND,
    GAP_MINUTE,
    GAP_HOUR,
    GAP_DAY,
};

class RollByTimeSink : public logslearn::LogSink
{
public:
    // 构造时存入文件名，并打开文件，将操作句柄管理起来
    RollByTimeSink(const std::string &basename, TimeGap gap_type) : _basename(basename)
    {
        switch (gap_type)
        {
        case TimeGap::GAP_SECOND:
            _gap_size = 1;
            break; // 以秒为时间段
        case TimeGap::GAP_MINUTE:
            _gap_size = 60;
            break; // 以分钟为时间段
        case TimeGap::GAP_HOUR:
            _gap_size = 3600;
            break; // 以小时为时间段
        case TimeGap::GAP_DAY:
            _gap_size = 3600 * 24;
            break; // 以天为时间段
        }
        _cur_gap = _gap_size == 1 ? logsLearn::util::Data::now() : logsLearn::util::Data::now() / _gap_size; // 获取当前是第几个时间段
        // 创建文件
        std::string filename = createNewFile();
        // 1.创建日志文件所在的目录,没有文件就创建文件
        logsLearn::util::File::createDirectory(logsLearn::util::File::path(filename));
        // 2.按特殊方式打开文件
        _ofs.open(filename, std::ios::binary | std::ios::app); // 打开文件 二进制可写可追加权限
        assert(_ofs.is_open());
    }
    // 将日志消息写入到标准输出，判断当前时间是否是当前文件的时间段，不是就要切换文件。
    void log(const char *data, size_t len)
    {
        time_t cur = logsLearn::util::Data::now(); // 获取当前系统时间,时间戳
        if ((cur / _gap_size) != _cur_gap)         // （每次写日志时判断当前的时间段与上次的时间段是否是一致得，一致的话就写入，不一致就创建新文件）
        {
            _ofs.close();                                                                                        // 打开文件，就必须关闭文件（这里关闭以前的文件）
            std::string pathname = createNewFile();                                                              // 创建新文件
            _cur_gap = _gap_size == 1 ? logsLearn::util::Data::now() : logsLearn::util::Data::now() / _gap_size; // 获取当前是第几个时间段
            _ofs.open(pathname, std::ios::binary | std::ios::app);                                               // 打开文件 二进制可写可追加权限
            assert(_ofs.is_open());                                                                              // 打开失败就报错
        }
        _ofs.write(data, len);
        assert(_ofs.good()); // 检测文件流状态和文件读写过程是否正常
    }

protected:
    // 创建一个新文件，不需要用户去创建，所有我们把权限设置为私有
    std::string createNewFile()
    {
        // 获取系统时间，以时间来构造文件名的扩展名
        time_t t = logsLearn::util::Data::now();
        struct tm lt;
        localtime_r(&t, &lt);
        std::stringstream filename;
        filename << _basename;
        filename << lt.tm_year + 1900;
        filename << lt.tm_mon + 1;
        filename << lt.tm_mday;
        filename << lt.tm_hour;
        filename << lt.tm_min;
        filename << lt.tm_sec;
        filename << ".log";
        return filename.str();
    }

private:
    std::string _basename; // 基本文件名
    std::ofstream _ofs;    // 会默认以写的方式打开文件
    size_t _cur_gap;       // 当前是第几个时间段
    size_t _gap_size;      // 时间段的大小
};
//进行功能测试

int main()
{
    std::unique_ptr<logslearn::LoggerBuilder> builder(new logslearn::GlobalLoggerBuilder());
    //建造者构建零部件
    builder->buildLoggerName("async_logger");
    builder->buildLoggerLevel(logslearn::loglevel::value::WARN);
    builder->buildLoggerFormatter("[%d{%H:%M:%S}][%t][%c][%p]%T%m%n");
    builder->buildLoggerType(logslearn::LoggerType::LOGGER_ASYNC);
    builder->buildSink<RollByTimeSink>("./logfile/roll-", TimeGap::GAP_SECOND); // 滚动文件落地方式,时间
    logslearn::Logger::ptr logger=builder->build();
    size_t cur=logsLearn::util::Data::now();
    while(logsLearn::util::Data::now()<cur+5){
        logger->fatal("这是一条测试日志");
        usleep(1000);
    }
    return 0;
}